import { Injectable } from '@angular/core';
import {
  Overlay,
  OverlayRef,
  OverlayConfig,
} from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';

import {
  MessageData,
  MessageDataFilled,
  MessageDataOptions,
} from './message.model';
import { MessageConfig } from './message-config.model';
import { MessageContainerComponent } from './message-container/message-container.component';

@Injectable()
export class fuiMessageService {

  private _idPrefix = 'message-';
  private _counter = 0; // Id counter for messages
  private _container: MessageContainerComponent;
  private _popupRef: OverlayRef;

  constructor(
    private overlay: Overlay,
  ) {}

  private createConatiner() {
    if (!this._popupRef) {
      const overlayConfig = new OverlayConfig();
      this._popupRef = this.overlay.create(overlayConfig);
    }

    const messageContainerPortal = new ComponentPortal(MessageContainerComponent);
    const messageContainerRef = this._popupRef.attach(messageContainerPortal);

    return messageContainerRef.instance;
  }

  private createMessage(message: MessageData, options?: MessageDataOptions): MessageDataFilled {
    if (!this._container) {
      this._container = this.createConatiner();
    }

    const resultMessage: MessageDataFilled = Object.assign(message, {
      messageId: this._generateMessageId(),
      options,
      createdAt: new Date(),
    });
    this._container.createMessage(resultMessage);

    return resultMessage;
  }

  private _generateMessageId(): string {
    return this._idPrefix + this._counter++;
  }

  /** Create a message of aribitrary type. */
  create(type: string, content: string, options?: MessageDataOptions): MessageDataFilled {
    return this.createMessage({ type: type as any, content }, options);
  }

  /** Create a success type of message. */
  success(content: string, options?: MessageDataOptions): MessageDataFilled {
    return this.createMessage({ type: 'success', content }, options);
  }

  /** Create a error type of message. */
  error(content: string, options?: MessageDataOptions): MessageDataFilled {
    return this.createMessage({ type: 'error', content }, options);
  }

  /** Create a info type of message. */
  info(content: string, options?: MessageDataOptions): MessageDataFilled {
    return this.createMessage({ type: 'info', content }, options);
  }

  /** Create a warning type of message. */
  warning(content: string, options?: MessageDataOptions): MessageDataFilled {
    return this.createMessage({ type: 'warning', content }, options);
  }

  /** Create a loading type of message. */
  loading(content: string, options?: MessageDataOptions): MessageDataFilled {
    return this.createMessage({ type: 'loading', content }, options);
  }

  /** Create a html type of message. Will render the html in the message content. */
  html(html: string, options?: MessageDataOptions): MessageDataFilled {
    return this.createMessage({ html }, options);
  }

}
